package com.threeox.commonlibrary.inject;

import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;

import com.threeox.commonlibrary.CommonApplcation;
import com.threeox.commonlibrary.inject.annotation.GetString;
import com.threeox.commonlibrary.inject.annotation.GetTag;
import com.threeox.commonlibrary.inject.annotation.GetView;
import com.threeox.commonlibrary.inject.annotation.InjectIntent;
import com.threeox.commonlibrary.inject.annotation.InvokeMethod;
import com.threeox.commonlibrary.inject.annotation.OnClick;
import com.threeox.commonlibrary.inject.annotation.OnTagClick;
import com.threeox.commonlibrary.ui.fragment.base.CommonFragment;
import com.threeox.commonlibrary.ui.view.impl.base.CommonModelExtend;
import com.threeox.utillibrary.util.EmptyUtils;
import com.threeox.utillibrary.util.IntentUtils;
import com.threeox.utillibrary.util.LogUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/** 
 *
 * @ClassName: Inject
 *
 * @Description: (View 注入的方法类)
 *
 * @author 赵屈犇
 *
 * @date 创建时间:2016/12/19 18:14 
 * 
 * @version 1.0
 */
@SuppressWarnings("Since15")
public class Inject {
	
	private static final String TAG = Inject.class.getName();

	private Object obj;
	private Field[] fields;
	private Method[] methods;
	private Class<? extends Object> cls;
	private CommonApplcation mApplcation;

	public static Inject init(Object obj) {
		return new Inject(obj);
	}

	private Inject(Object obj) {
		this.obj = obj;
		this.cls = obj.getClass();
		this.fields = cls.getDeclaredFields();
		this.methods = cls.getDeclaredMethods();

		this.mApplcation = CommonApplcation.getInstance();
	}

	/**
	 * 初始化View
	 * 
	 * @return
	 */
	public Inject initView() {
		for (Field field : fields) {
			boolean isGetView = field.isAnnotationPresent(GetView.class);
			boolean isGetStr = field.isAnnotationPresent(GetString.class);
			if (!isGetView && !isGetStr) {
				continue;
			}
			getView(obj, field, isGetView);
		}
		return this;
	}

	/**
	 * 初始化View 根据View
	 * 
	 * @param view
	 * @return
	 */
	public Inject initView(View view) {
		for (Field field : fields) {
			boolean isGetView = field.isAnnotationPresent(GetView.class);
			boolean isGetStr = field.isAnnotationPresent(GetString.class);
			if (!isGetView && !isGetStr) {
				continue;
			}
			getView(view, field, isGetView);
		}
		return this;
	}

	/**
	 * 初始化String
	 * 
	 * @return
	 */
	public Inject initString() {
		for (Field field : fields) {
			boolean isGetStr = field.isAnnotationPresent(GetString.class);
			if (!isGetStr) {
				continue;
			}
			getString(obj, field, isGetStr);
		}
		return this;
	}

	/**
	 * 根据Tag初始化View
	 * 
	 * @param view
	 * @return
	 */
	public Inject initTagView(View view) {
		for (Field field : fields) {
			boolean isGetTag = field.isAnnotationPresent(GetTag.class);
			if (!isGetTag) {
				continue;
			}
			GetTag getTag = field.getAnnotation(GetTag.class);
			String tag = getTag.value();
			try {
				field.setAccessible(true);
				field.set(obj, view.findViewWithTag(tag));
				LogUtils.d(TAG, field.getName() + "-->GetTag注入成功;");
			} catch (Exception e) {
				LogUtils.e(TAG, field.getName() + "-->GetTag注入失败:" + e.getMessage());
			}
		}
		return this;
	}

	/**
	 * 初始化点击事件
	 */
	public Inject initClick() {
		for (final Method method : methods) {
			boolean isOnClick = method.isAnnotationPresent(OnClick.class);
			if (!isOnClick) {
				continue;
			}
			onClick(obj, method, isOnClick);
		}
		return this;
	}

	/**
	 * 初始化TagClick
	 * 
	 * @param view
	 * @return
	 */
	public Inject initTagClick(View view) {
		for (final Method method : methods) {
			boolean isGetTag = method.isAnnotationPresent(OnTagClick.class);
			if (!isGetTag) {
				continue;
			}
			OnTagClick onTagClick = method.getAnnotation(OnTagClick.class);
			String tag = onTagClick.value();
			try {
                View v = view.findViewWithTag(tag);
				if (v != null) {
                    v.setOnClickListener(new OnClickListener() {
						@Override
						public void onClick(View v) {
						try {
							method.invoke(obj);
						} catch (Exception e) {
							LogUtils.e("onClick注入失败:" + method.getName());
						}
						}
					});
				}
			} catch (Exception e) {
				LogUtils.e(TAG, method.getName() + "-->GetTag注入失败:" + e.getMessage());
			}
		}
		return this;
	}
	
	/**
	 * 注入方法
	 *
	 * @param view
	 * @return
	 */
	public Inject invokeMethod(View view){
		for (Field field : fields) {
			try {
				boolean isInvokeMethod = field.isAnnotationPresent(InvokeMethod.class);
				if (!isInvokeMethod) {
					continue;
				}
				InvokeMethod invokeMethod = field.getAnnotation(InvokeMethod.class);
				field.setAccessible(true);
				Object[] data = (Object[]) field.get(obj);
				injectMethod(invokeMethod, view, data);
			} catch (Exception e) {
				LogUtils.e(TAG,field.getName() + "-->invokeMethod注入失败:" + e.getMessage());
			}
		}
		
		for (final Method method : methods) {
			try {
				boolean isInvokeMethod = method.isAnnotationPresent(InvokeMethod.class);
				if (!isInvokeMethod) {
					continue;
				}
				InvokeMethod invokeMethod = method.getAnnotation(InvokeMethod.class);
				injectMethod(invokeMethod, view , null);
				// method.invoke(invokeMethod, args);
			} catch (Exception e) {
				LogUtils.e(TAG,method.getName() + "-->invokeMethod注入失败:" + e.getMessage());
			}
		}
		return this;
	}

	private void injectMethod(InvokeMethod invokeMethod, View view, Object[] param) throws Exception{
		String tag = invokeMethod.tag();
		if (EmptyUtils.isNotEmpty(tag)) {
			view = view.findViewWithTag(tag);
		} else {
			view = getViewById(obj, invokeMethod.value());
		}
		if (view != null) {
			Class<? extends View> _ViewCls = view.getClass();
			Class[] parameters = invokeMethod.parameters();
			Method viewMethod = null;
			try {
                viewMethod = _ViewCls.getMethod(invokeMethod.method(), parameters);
			} catch (Exception e) {
				Method[] methods = _ViewCls.getMethods();
				for (Method method : methods) {
					if (invokeMethod.method().equals(method.getName())) {
                        viewMethod = method;
						continue;
					}
				}
			}
			if (viewMethod != null) {
				Object[] obj = null;
				if (param == null) {
					if (parameters != null && parameters.length > 0) {
						obj = new Object[parameters.length];
						for (int i = 0; i < parameters.length; i++) {
							obj[i] = parameters[i].newInstance();
						}
					}
				} else {
					obj = param;
				}
                viewMethod.invoke(view, obj);
			} else {
				LogUtils.d(TAG,"invokeMethod注入失败:得不到方法");
			}
		} else {
			LogUtils.d(TAG, "invokeMethod注入失败:得不到View");
		}
	}

	/**
	 * 点击事件
	 * 
	 * @param obj
	 * @param method
	 * @param isOnClick
	 */
	private void onClick(final Object obj, final Method method, boolean isOnClick) {
		if (isOnClick) {
			OnClick onClick = method.getAnnotation(OnClick.class);
			int id = onClick.value();
			View view = getViewById(obj, id);
			if (view != null) {
				method.setAccessible(true);
				view.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						try {
							method.invoke(obj);
						} catch (Exception e) {
							LogUtils.e("onClick注入失败:" + method.getName());
						}
					}
				});
			}
		}
	}

	/**
	 * 根据Id 得到String
	 * 
	 * @param obj
	 * @param field
	 * @param isGetStr
	 */
	private void getString(Object obj, Field field, boolean isGetStr) {
		if (isGetStr) {
			GetString getString = field.getAnnotation(GetString.class);
			int id = getString.value();
			try {
				field.setAccessible(true);
				String value = mApplcation.getString(id);
				field.set(obj, value);
				LogUtils.d(TAG, field.getName() + "-->GetString注入成功;value:" + value);
			} catch (Exception e) {
				LogUtils.e(TAG, field.getName() + "-->GetString注入失败:" + e.getMessage());
			}
		}
	}

	/**
	 * 得到View 根据Id
	 * 
	 * @param obj
	 * @param field
	 * @param isGetView
	 */
	private void getView(Object obj, Field field, boolean isGetView) {
		if (isGetView) {
			GetView getView = field.getAnnotation(GetView.class);
			int id = getView.value();
			try {
				View view = null;
				if (obj instanceof Activity) {
					view = ((Activity) obj).findViewById(id);
				} else if (obj instanceof View) {
					view = ((View) obj).findViewById(id);
				} else if (obj instanceof CommonFragment) {
					view = ((CommonFragment) obj).findViewById(id);
				} else if (obj instanceof CommonModelExtend) {
					view = ((CommonModelExtend) obj).findViewById(id);
				} else {
					Method method = obj.getClass().getMethod("findViewById", int.class);
					view = (View) method.invoke(obj, id);
				}
				if (view != null) {
					field.setAccessible(true);
					field.set(obj, view);
					LogUtils.d(TAG, field.getName() + "-->GetView注入成功;");
				} else {
					LogUtils.d(TAG, field.getName() + "-->GetView注入失败 值为null;");
				}
			} catch (Exception e) {
				LogUtils.e(TAG, field.getName() + "-->GetView注入失败:" + e.getMessage());
			}
		}
	}

	private View getViewById(Object obj, int id) {
		try {
			if (obj instanceof Activity) {
				return ((Activity) obj).findViewById(id);
			} else if (obj instanceof View) {
				return ((View) obj).findViewById(id);
			} else if (obj instanceof CommonFragment) {
				return ((CommonFragment) obj).findViewById(id);
			} else if (obj instanceof CommonModelExtend) {
				return ((CommonModelExtend) obj).findViewById(id);
			} else {
				Method method = obj.getClass().getMethod("findViewById", int.class);
				return (View) method.invoke(obj, id);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

    /**
     * 初始化Intent 附值
     *
     * @param intent
     */
	public void initIntentValue(Intent intent) {
	    if (EmptyUtils.isNotEmpty(fields)) {
            for (Field field : fields) {
                boolean isInjectIntent = field.isAnnotationPresent(InjectIntent.class);
                if (!isInjectIntent) {
                    continue;
                }
                initIntentValue(intent, field, isInjectIntent);
            }
        }
    }

    /**
     * 自动注入Intent的值
     *
     * @param intent
     * @param field
     * @param isInjectIntent
     */
    private void initIntentValue(Intent intent, Field field, boolean isInjectIntent) {
        if (isInjectIntent) {
            InjectIntent injectIntent = field.getAnnotation(InjectIntent.class);
            String key = injectIntent.value();
            try {
                Object value = IntentUtils.get(intent, key);
                if (EmptyUtils.isNotEmpty(value)) {
                    field.setAccessible(true);
                    field.set(obj, value);
                    LogUtils.d(TAG, field.getName() + "-->initIntentValue注入成功;");
                }
            } catch (Exception e) {
                LogUtils.e(TAG, field.getName() + "-->initIntentValue注入失败:" + e.getMessage());
            }
        }
    }


}
